package com.gopay.common.trace.helper;

import com.gopay.common.trace.LogConst;
import com.gopay.common.trace.TraceLog;
import com.gopay.common.trace.TraceLogUtils;
import com.gopay.common.trace.def.Tracer;
import com.gopay.common.trace.enums.TraceType;
import com.gopay.common.trace.hessian.HessianHeaderContext;
import com.gopay.common.trace.support.LogContext;
import com.gopay.common.trace.util.SamplingUtils;
import com.gopay.common.util.HttpRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.support.AopUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * @author ddh02
 * @LogRpcServerHelper
 * @2017/5/19 9:22  www.gopay.com.cn Inc.All rights reserved.
 */


public class LogRpcServerHelper extends LogAbstractHelper {
    @Override
    public void before(Object... args) {

        try {
            HttpServletRequest request = (HttpServletRequest) args[0];

           // String spanName = "";//AopUtils.getTargetClass(this.getService()).getSimpleName() + request.getPathInfo();



            //rpc 服务接收之前 先 清空 本地线程 相关的 变量
            logContext.clearThreadLocal();
            //接收开始
            handleHessianHeader(request);

            tid = logContext.getTid(); //重新获取

            spanName = HessianHeaderContext.getContext().getHeader(LogConst.SPANNAME);
            if (StringUtils.isNotBlank(tid)) {
                Integer count = LogContext.getContext().incrCount();
                String pid = HessianHeaderContext.getContext().getHeader(LogConst.SPANID);
                span = tracer.genSpan(tid, pid, spanName, TraceType.RPC);

                logContext.setSpan(count, span);

                //sr
                tracer.serverReceive(span, null, startTime);
            }
        } catch (Exception e) {
            printSelfException(e, "rpc服务端 before 阶段自身异常！");
        }
    }

    @Override
    public void after(Object... args) {
        try {

            long end = System.currentTimeMillis();

            if (StringUtils.isBlank(tid)) {
                if(SamplingUtils.isSelected()){
                    /*logger.info("hessian {} excute sr={} ss={} time = {}",
                            new Object[]{AopUtils.getTargetClass(this.getService()).getSimpleName() + request.getPathInfo(),
                                    start, end, end - start});*/

                    //// TODO: 2017/5/16
                    TraceLogUtils.log(new TraceLog(TraceType.RPC, end - startTime, spanName));

                }
            } else {
                LogContext.getContext().dncrCount(); ///计数减一
                tracer.serverSend(span, null, end);  //ss
                Tracer.getTracer().endAndShow(span);
            }

        } catch (Exception e) {
            printSelfException(e, "rpc服务端 after 阶段自身异常！");
        } finally {
            HessianHeaderContext.close();  //清空线程资源
        }

    }

    @Override
    public void ex(Throwable throwable) {

        commonProcessEx(throwable);
    }

    @Override
    public TraceType getTraceType() {
        return TraceType.RPC;
    }


    /**
     * 注意 此处可以使用 serviceContext 类 来获取 header
     * 处理hessian header
     * @param request
     */
    protected void handleHessianHeader(HttpServletRequest request) {
        HessianHeaderContext context = HessianHeaderContext.getContext();
        Enumeration enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement().toString();
            String value = request.getHeader(name);

//            System.out.println("name="+ name +", value=" + value);
            if (LogConst.TID.equals(name)
                    || LogConst.SPANID.equals(name)
                    || LogConst.SPANNAME.toLowerCase().equals(name)
                    ) {
                    //header 的 name  过来都会变成小写...
                // logger.info("receive tid = {} {}" , new Object[]{value, AopUtils.getTargetClass(this.getService()).getSimpleName()+ request.getPathInfo()} );
                context.addHeader(name, value);
            }
        }

        //将tid 放入 本地线程变量中
        if ((StringUtils.isNotBlank(context.getHeader(LogConst.TID)))) {
            LogContext.getContext().setTid(context.getHeader(LogConst.TID));
        }
    }

}
